package com.gt.self.service.impl;

import com.gt.common.AjaxResult;
import com.gt.common.CountAgeUtil;
import com.gt.common.DateUtils;
import com.gt.common.GenerateUtil;
import com.gt.common.SelfStatus;
import com.gt.exception.SelfServiceException;
import com.gt.self.domain.AppBillTable;
import com.gt.self.domain.UsBookBillNew;
import com.gt.self.domain.UsBookPat;
import com.gt.self.domain.UsCheckPartItem;
import com.gt.self.domain.UsReportInfo;
import com.gt.self.domain.vo.DevCardNoInfo;
import com.gt.self.domain.vo.ReportInfoVo;
import com.gt.self.domain.vo.ReportParamVo;
import com.gt.self.service.AppBillTableService;
import com.gt.self.service.SelfMachineService;
import com.gt.self.service.UsBookBillNewService;
import com.gt.self.service.UsBookPatService;
import com.gt.self.service.UsCheckPartItemService;
import com.gt.self.service.UsReportInfoService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

@Slf4j
@Service
public class SelfMachineServiceImpl implements SelfMachineService {

    @Autowired
    private UsBookPatService usBookPatService;

    @Autowired
    private AppBillTableService appBillTableService;

    @Autowired
    private UsCheckPartItemService usCheckPartItemService;

    @Autowired
    private UsBookBillNewService usBookBillNewService;

    @Autowired
    private UsReportInfoService usReportInfoService;


    /**
     * 自助报道(通过病人id)
     *
     * @param commonNo
     * @return
     */
    @Override
    public AjaxResult selfServiceReport(String commonNo) {

        boolean statusFlag = false;//状态标志：当返回数据为空时，判断是否是报道状态
        List<ReportInfoVo> reportInfoVos = new ArrayList<>();
        ReportInfoVo reportInfoVo = new ReportInfoVo();

        List<AppBillTable> appBillTables = appBillTableService.selectApplyBillInfo(commonNo);

        if (appBillTables == null || appBillTables.size() < 1) {
            log.error("无预约信息，请先挂号，请求信息：[{}]", commonNo);
            return AjaxResult.error(SelfStatus.NO_BOOK, "无预约信息，请先挂号！");
        }

        //获取申请单号
        List<String> regNoList = appBillTables.stream()
                .map(AppBillTable::getRegNo).distinct().collect(Collectors.toList());

        //只有一个申请单情况
        if (regNoList.size() == 1){
            String regNo = regNoList.get(0);
            UsBookPat usBookPat = usBookPatService.queryByApplyBillNo(regNo);
            if (usBookPat != null){
                if (StringUtils.isNotBlank(usBookPat.getAuditstatus()) && (usBookPat.getAuditstatus().equals("激活") ||  usBookPat.getAuditstatus().equals("候诊"))){
                    log.error("已报道，请不要重复报道：[{}]",commonNo);
                    statusFlag = true;
                    return AjaxResult.error(SelfStatus.REPEAT_REPORT, "已报道，请不要重复报道！");
                }
                if (StringUtils.isNotBlank(usBookPat.getAuditstatus()) && usBookPat.getAuditstatus().equals("诊断")){
                    log.error("无预约信息，请先挂号，请求信息：[{}]", commonNo);
                    return AjaxResult.error(SelfStatus.NO_BOOK, "无预约信息，请先挂号！");
                }
                usBookPat.setAuditstatus("激活");
                usBookPat.setCheckintime(new Date());
                usBookPatService.updateBookPat(usBookPat);
                reportInfoVo = creatData(usBookPat);
                reportInfoVos.add(reportInfoVo);
                return AjaxResult.success(reportInfoVos);
            }
        }
        //申请号有多个情况
        for (String regNo : regNoList) {

            UsBookPat usBookPat = usBookPatService.queryByApplyBillNo(regNo);
            if (usBookPat != null){
                if (StringUtils.isNotBlank(usBookPat.getAuditstatus()) && (usBookPat.getAuditstatus().equals("激活") || usBookPat.getAuditstatus().equals("诊断"))){
                    if (StringUtils.isNotBlank(usBookPat.getAuditstatus()) && (usBookPat.getAuditstatus().equals("激活") ||  usBookPat.getAuditstatus().equals("候诊"))){
                        log.error("已报道，请不要重复报道：[{}]",regNo);
                        continue;
                    }
                    if (StringUtils.isNotBlank(usBookPat.getAuditstatus()) && usBookPat.getAuditstatus().equals("诊断")){
                        log.error("无预约信息，请先挂号，请求信息：[{}]", commonNo);
                        continue;
                    }
                    usBookPat.setAuditstatus("激活");
                    usBookPat.setCheckintime(new Date());
                    usBookPatService.updateBookPat(usBookPat);
                    reportInfoVo = creatData(usBookPat);
                    reportInfoVos.add(reportInfoVo);
                    continue;
                }
            }
            //根据申请单号匹配对应的单子
            List<AppBillTable> appBillTableList = appBillTables.stream()
                    .filter(appBillTable -> appBillTable.getRegNo().equals(regNo))
                    .collect(Collectors.toList());

            //根据申请单号+检查项目编号组合属性去重，这个为了防止重复数据
            List<AppBillTable> appBills = appBillTableList.stream()
                    .collect(collectingAndThen(toCollection(() -> new TreeSet<>(Comparator.comparing(AppBillTable::getAdmSerialNum))), ArrayList<AppBillTable>::new));

            reportInfoVo = createRepotBill(appBills);
            reportInfoVos.add(reportInfoVo);
        }
        if (reportInfoVos.size() < 1){
            if (statusFlag){
                log.error("已报道，请不要重复报道：[{}]",commonNo);
                return AjaxResult.error(SelfStatus.REPEAT_REPORT, "已报道，请不要重复报道！");
            }
            log.error("无预约信息，请先挂号，请求信息：[{}]", commonNo);
            return AjaxResult.error(SelfStatus.NO_BOOK, "无预约信息，请先挂号！");
        }

        return AjaxResult.success(reportInfoVos);
    }

    private ReportInfoVo createRepotBill(List<AppBillTable> appBills) {
        ReportInfoVo reportInfoVo = new ReportInfoVo();
        UsBookPat usBookPat = new UsBookPat();
        String regNo = appBills.get(0).getRegNo();
        String shebaohao = "";
        String itemd = "";
        //检查项目
        String checkitem = "";
        //实收费用、应收费用
        String price = "";
        String uuid = String.valueOf(GenerateUtil.uuid());
        for (AppBillTable appbillTableItem : appBills) {
            //检查项目编号
            String Itemcode = appbillTableItem.getArcimCode();
            //检查项目名称
            String Itemname = appbillTableItem.getOrdName();

            //检查项目单价
            String ordPrice = appbillTableItem.getOrdPrice() == null ? "0" : appbillTableItem.getOrdPrice();
            BigDecimal bigD1 = new BigDecimal(ordPrice);
            price += bigD1;

            //预约表检查项目
            checkitem = checkitem + "," + Itemname;

            //判断是否有该检查项目 没有则添加
            UsCheckPartItem usCheckPartItems = usCheckPartItemService.queryByIdCheckPartItem(Itemcode, String.valueOf(appBills.get(0).getArcItemCat()));
            if (usCheckPartItems == null) {
                UsCheckPartItem usCheckpartItem = new UsCheckPartItem();
                itemd = GenerateUtil.publicSerialNumber();
                usCheckpartItem.setId(itemd);
                //检查子类    ArcItemCat
                usCheckpartItem.setPartname(appBills.get(0).getArcItemCat());
                usCheckpartItem.setItemId(Itemcode);
                usCheckpartItem.setItemName(Itemname);
                usCheckpartItem.setCheckTypeKey("check_project_type");
                usCheckpartItem.setForcedStructure("0");
                usCheckpartItem.setHospitalId("128");
                usCheckpartItem.setIsReportSetFlag("否");
                usCheckPartItemService.insertCheckPartItem(usCheckpartItem);
            } else {
                itemd = usCheckPartItems.getId();
            }
            shebaohao += itemd + ";";
            UsBookBillNew usBookBillNew = new UsBookBillNew();
            usBookBillNewService.deleteById(appbillTableItem.getRegNo(), Itemcode);
            usBookBillNew.setPatOrdrowid(uuid);
            usBookBillNew.setBillStudyno(appbillTableItem.getRegNo());
            usBookBillNew.setCheckStatus("已登记");
            usBookBillNew.setIdType(Itemcode);
            usBookBillNew.setOrdName(Itemname);
            usBookBillNewService.insertBookBillNew(usBookBillNew);

        }
        //病人号
        usBookPat.setPatid(appBills.get(0).getPatientId());
        //姓名
        usBookPat.setPatname(appBills.get(0).getName());
        //性别
        usBookPat.setPatsex(appBills.get(0).getSex());
        //年龄
        usBookPat.setPatage(appBills.get(0).getAge());
        Matcher matcher = Pattern.compile("(\\d+)岁").matcher(appBills.get(0).getAge());
        Integer age = matcher.find() ? Integer.parseInt(matcher.group(1)) : 0;
        //地址
        usBookPat.setAddress(appBills.get(0).getAddress());
        //出生日期
        usBookPat.setBorthdate(appBills.get(0).getBirthday());
        //岁月天
        Map<String, Object> syt = CountAgeUtil.countAge(appBills.get(0).getBirthday());
        //送检科室
        usBookPat.setOrderdept(appBills.get(0).getOrdLoc());
        //费用状态 申请单费用状态
        usBookPat.setOther2(Integer.valueOf(appBills.get(0).getOrdBillStatus()));
        usBookPat.setShebaohao(shebaohao);
        //申请单号
        usBookPat.setHisId(regNo);
        //申请医师
        usBookPat.setOrderdoctor(appBills.get(0).getOrdDoctor());
        usBookPat.setClinicalDiagnosis(appBills.get(0).getClinicDiagnose());
        //ordrowid
        usBookPat.setOrdrowid(uuid);
        //病史
        usBookPat.setPathis(appBills.get(0).getClinicDisease());
        //联系电话
        usBookPat.setTelephone(appBills.get(0).getTelephone());
        //主诉
        usBookPat.setPatview(appBills.get(0).getOperationinfo());
        //检查项目
        usBookPat.setCheckitem(checkitem.replaceFirst(",", ""));
        // 实收费用
        usBookPat.setCheckfee(appBills.get(0).getCharges());
        //预约的检查日期
        usBookPat.setCheckdate(DateUtils.getDate(new Date(), "yyyy-MM-dd"));
        //检查子类
        usBookPat.setShiyuan(appBills.get(0).getArcItemCat());
        //申请单号
        usBookPat.setPanno(regNo);
        //申请日期
        usBookPat.setPlanviewdate(new Date());
        //身份证
        usBookPat.setIdcard(appBills.get(0).getCredentialNo());
        //优先号
        usBookPat.setYingchang(0);
        //医院id
        usBookPat.setHospitalId("128");
        //应收费用
        usBookPat.setPayableCharge(appBills.get(0).getCharges());
        //创建时间
        usBookPat.setCratedate(DateUtils.getDateTime());
        //登记时间
        usBookPat.setCheckstartdate(new Date());

        // todo 检查区域，这里不能确认检查区域，也就无法获取yuci，需要后续确认，此处默认给26
        usBookPat.setYuci(Integer.valueOf("26"));
        // todo 预约时段
        usBookPat.setAuditdoctor(DateUtils.dateFormaHms(String.valueOf("093000")) + "~" + DateUtils.dateFormaHms(String.valueOf("100000")));
        //todo 检查室id checkRoomId
        usBookPat.setCheckroomid("us_20220824201253385066");
        //todo 检查室名称 checkRoomId
        usBookPat.setCheckroom("一号诊室");
        //todo 队列名称
        usBookPat.setChecktypename("");
        // todo 病人来源,此处无法确认来源，后续增加,默认给o
        String patSource = "o";
        switch (patSource) {
            case "o":
                //门诊号
                usBookPat.setMzno(appBills.get(0).getStudyNo());
                usBookPat.setPatsource(0);
                break;
            case "i":
                usBookPat.setInputno(appBills.get(0).getStudyNo());
                usBookPat.setPatsource(1);
                break;
            case "e":
                usBookPat.setPatsource(2);
                break;
            case "体检":
                usBookPat.setPatsource(3);
                break;
            default:
                usBookPat.setPatsource(4);
                break;
        }
        //获取排队号和排队人数
        DevCardNoInfo devCardNoInfo = getDevCardNoAndWaitCount(null, age, 26, regNo);
        usBookPat.setAuditstatus("激活");
        usBookPat.setYingchang(devCardNoInfo.getYingchang());
        usBookPat.setDevcardno(devCardNoInfo.getDevCardNo());
        usBookPat.setCheckno("A" + GenerateUtil.serialNumber());
        usBookPat.setChecktype("us_20210125154044208624");
        usBookPat.setCheckintime(new Date());
        int save = usBookPatService.insertBookPat(usBookPat);

        if (save <= 0) {
            log.error("保存异常，申请单号：[{}]",regNo);
            return null;
        }
        reportInfoVo = createViewData(usBookPat, devCardNoInfo);
        return reportInfoVo;
    }


    /**
     * 保存报道信息
     *
     * @param reportInfoVo
     */
    private void saveReportInfo(ReportInfoVo reportInfoVo) {
        UsReportInfo usReportInfo = new UsReportInfo();
        BeanUtils.copyProperties(reportInfoVo, usReportInfo);
        usReportInfo.setReportStatus("报道成功");
        usReportInfoService.save(usReportInfo);
    }

    /**
     * 判断是否是今天预约的申请单，如果不是不可以报道
     *
     * @param bookDate
     * @return
     */
    private boolean noTodayBook(String bookDate) {
        //预约时间
        Date date = DateUtils.parseDate(bookDate);
        //当天时间
        LocalDate today = LocalDate.now();
        Date beforeDay = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
        //后一天
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, 1);
        Date nextDay = calendar.getTime();
        if (date.getTime() < beforeDay.getTime() || date.getTime() > nextDay.getTime()) {
            return true;
        }
        return false;
    }

    /**
     * 构造前端返回的数据
     *
     * @param usBookPat
     * @return
     */
    private ReportInfoVo createViewData(UsBookPat usBookPat, DevCardNoInfo devCardNoInfo) {
        ReportInfoVo reportInfoVo = new ReportInfoVo();
        reportInfoVo.setApplyNo(usBookPat.getHisId());
        reportInfoVo.setCheckProject(usBookPat.getCheckitem());
        reportInfoVo.setWaitNo(devCardNoInfo.getDevCardNo());
        reportInfoVo.setWaitCount(devCardNoInfo.getWaitCount());
        reportInfoVo.setCheckRoom(usBookPat.getCheckroom());
        reportInfoVo.setReportTime(new Date());
        reportInfoVo.setPatientId(usBookPat.getPatid());
        reportInfoVo.setPatientName(usBookPat.getPatname());
        reportInfoVo.setSex(usBookPat.getPatsex());
        reportInfoVo.setAge(usBookPat.getPatage());
        reportInfoVo.setIdCardNo(usBookPat.getIdcard());
        reportInfoVo.setWaitTime("10");
        reportInfoVo.setBirthday(usBookPat.getBorthdate() != null ? usBookPat.getBorthdate().replace("-", "/") : "");
        reportInfoVo.setReportStatus(SelfStatus.SUCCESS);
        saveReportInfo(reportInfoVo);
        return reportInfoVo;
    }

    /**
     * 构造前端返回的数据
     *
     * @param usBookPat
     * @return
     */
    private ReportInfoVo creatData(UsBookPat usBookPat) {
        ReportInfoVo reportInfoVo = new ReportInfoVo();
        reportInfoVo.setApplyNo(usBookPat.getHisId());
        reportInfoVo.setCheckProject(usBookPat.getCheckitem());
        reportInfoVo.setWaitNo(usBookPat.getDevcardno());
        Random random = new Random();
        int waitCount = random.nextInt(20) + 1;
        reportInfoVo.setWaitCount(waitCount);
        reportInfoVo.setCheckRoom(usBookPat.getCheckroom());
        reportInfoVo.setReportTime(new Date());
        reportInfoVo.setPatientId(usBookPat.getPatid());
        reportInfoVo.setPatientName(usBookPat.getPatname());
        reportInfoVo.setSex(usBookPat.getPatsex());
        reportInfoVo.setAge(usBookPat.getPatage());
        reportInfoVo.setIdCardNo(usBookPat.getIdcard());
        reportInfoVo.setWaitTime("10");
        reportInfoVo.setBirthday(usBookPat.getBorthdate() != null ? usBookPat.getBorthdate().replace("-", "/") : "");
        reportInfoVo.setReportStatus(SelfStatus.SUCCESS);
        saveReportInfo(reportInfoVo);
        return reportInfoVo;
    }
    /**
     * 获取排队号和排队人数
     **/
    private DevCardNoInfo getDevCardNoAndWaitCount(String checkType, Integer age, Integer yuci, String regNo) {
        DevCardNoInfo devCardNoInfo = new DevCardNoInfo();
        String devCardNo = null;
        String checkTypeNo = null;
        int yingchang = 0;
        if (checkType == null) {
            log.error("检查类别为null,申请单号为：{}", regNo);
            checkTypeNo = "A";
        } else {
            //获取检查类型号
            checkTypeNo = usBookPatService.checkTypeNo(checkType);
        }
        //获取排队号
        UsBookPat usBookPat = usBookPatService.getDevCardNo(DateFormatUtils.format(new Date(), "yyyy-MM-dd"), checkTypeNo, yuci);
        //获取排队人数
        int waitCount = usBookPatService.getWaitNum(DateFormatUtils.format(new Date(), "yyyy-MM-dd"), checkTypeNo, yuci);

        if (usBookPat == null) {
            devCardNo = checkTypeNo + "001";
        } else {
            devCardNo = usBookPat.getDevcardno().replace("优", "");
            int no = Integer.parseInt(devCardNo.substring(1, devCardNo.length())) + 1;
            devCardNo = checkTypeNo + String.format("%03d", no);
        }

        if (age >= 70) {
            devCardNo = "优" + devCardNo.replaceAll("优", "");
            yingchang = 1;
        }
        devCardNoInfo.setDevCardNo(devCardNo);
        devCardNoInfo.setYingchang(yingchang);
        devCardNoInfo.setWaitCount(waitCount);
        return devCardNoInfo;
    }

}
